SpyneJS

SIX YEARS IN FORTUNE 100 PRODUCTION · OPEN SOURCE AI-Native
Application Structure

Rules-based code generation.
Precise, verifiable, and consistent

Learn from Examples
  • Evolve applications without the guesswork

    SpyneJS replaces ambiguous patterns with rules that can express the full range of web experiences: clear roles for each part of an application, and a known place for every feature.

  • Runs anywhere, connects to your systems

    A SpyneJS application is complete and self-contained, and deploys on any hosting infrastructure. The databases, APIs, and services you already run enter as declared channels.

THE FRAMEWORK A complete structural language for developers and agents.

Display and behavior are declared and wired together to define what the application does, and kept separate from content. Every agent, every session, every model reads the same complete definition.

The codebase becomes the spec — it evolves with every change, and developers and agents can read it at the source.

Works with the AI models you already use.

Every SpyneJS template ships with generative grammar. A model's knowledge of the web — HTML, CSS, JavaScript, and the specifications behind them — is applied directly to a rules-based structure, removing the noise from generated code. Content remains fully expressive.

npx spyne-cli create-app — then npm start. Same workflow, same tools.

THE PATTERN VBL — View, Behavior, Logic.

Every web application can be expressed in three layers: View — what displays; Behavior — events and data; Logic — what makes it run. Views and Behavior are wired to each other, and both draw their methods from Logic. Structure is written, never guessed. This is how the Codebase becomes the Spec.

  • Real DOM, declarative Views — each View renders, syncs its content, and nests other Views, every region owned and updated independently. No reconciliation layer. The framework handles rendering through observable chaining and automation.
  • Wiring you can read — every connection between Behavior and Views lives in the code, visible before anything runs.
  • Outside content joins the stream — data, external events, and plugins enter through Channels and run as native behavior.
  • One rule at every scale — the same composition from hello world to the full application.

Hello World — View, Behavior, Logic

The minimal VBL pattern. No hidden lifecycle logic, no implicit control flow — what renders, what moves, and what decides are separated and visible from the start.

Hello World – View, Behavior, Logic

This example shows the minimal, explicit form of the VBL pattern — a ViewStream, a SpyneTrait, and a UI Channel working together with no hidden lifecycle logic or implicit control flow.

Each responsibility is visible and self-contained. What renders, what reacts, and what decides are separated clearly, making the structure easy to follow and reason about as it runs in the browser.

The same relationships shown here — between view, behavior, and logic — are used unchanged as applications grow in complexity, depth, and scope.

Why This Matters:
This example already contains the full architectural model. Nothing is added later to make it scale — complexity accumulates through composition, not through new abstractions. That continuity is what allows applications to remain understandable over time, and what makes SpyneJS a stable foundation for both human and AI-assisted development.

    class MainView extends ViewStream {
      constructor(props = {}) {
        
        // VIEW:          ADD CONTENT
        props.template =  `<h2></h2>
                           ​<button>Click Me</button>`;                           
         
        // BEHAVIOR:      ADD CHANNELS
        props.channels =  ["CHANNEL_UI"];    
        
        // LOGIC:         ADD METHODS
        props.traits =    [HelloWorldTrait];    
        super(props);
      }
    
      // BEHAVIOR: CONNECT EVENTS TO METHODS  
      addActionListeners() {
        return [["CHANNEL_UI_CLICK_EVENT", "hw$greet"]];
      }
    
      // BEHAVIOR: SEND LOCAL EVENTS
      broadcastEvents() {
        return [["button", "click"]];
      }
    
      // RENDER HOOK
      onRendered() {
        this.hw$greet();
      }
    }
    
    new MainView().appendToDom(document.body);
  •   class HelloWorldTrait extends SpyneTrait {
        constructor(context) {
        
          // LOGIC: Binds pure functions
          super(context, "hw$");
        }
      
        // Trait method that rotates the array
        static hw$greet() {
          // Initialize the greetings array once, 
          storing it in props
          if (!this.props.greetings) {
            this.props.greetings = [
              "Hello World", "Hola Mundo", "Bonjour le monde", 
              "Hallo Welt", "こんにちは世界", "你好,世界", 
              "안녕하세요 월드", "Привіт, світе", "مرحبا بالعالم", 
              "Olá Mundo", "Ciao Mondo"
            ];
          }
      
          // Remove the first item
          const currentGreeting = this.props.greetings.shift();
          // Update the UI
          this.props.el$("h2").el.innerText = currentGreeting;
          // Re-insert the item at the end to cycle
          this.props.greetings.push(currentGreeting);
        }
      }
            

The same relationships shown here scale unchanged as the application grows in complexity, depth, and scope.

APPLICATION SHELL Start with a complete application.

The Application Shell is a running SpyneJS application, pre-wired: an app model, full configuration, and the standard plugins installed.

  • CMS

    Author content — and exchange data with AI — where the application runs. Local JSON files are the database: versionable with the repo, no external service.

  • Behavior Console

    Every channel, every event, every payload — streaming live as the application runs. The structure describes itself in real time.

  • Spyne-CLI

    Scaffold, serve, and build from the command line. create-app builds the initial app from your prompt, and can generate VBL code as your app evolves.

Every setting you choose is captured as structured data — routes, window behavior, runtime flags — declared and embedded in what you download. The generative grammar is already inside: your AI tools read it from the first prompt.

Keep the editor, the agents, and the workflow you have. The Shell adds the application.

Build a configuration →

PLUGINS Expand your app

A SpyneJS plugin is a complete SpyneJS application — the same VBL pattern, plus hooks for integration. It connects to the host's single configuration and behaves like everything else in the host.

The web is wider than any framework — services, libraries, design systems, running products. Plugins are how SpyneJS reaches it: external behavior enters through Channels and joins the stream; nothing reaches farther than its declared connections.

The same shape travels the other way. Components, themes, and working features move between applications as plugins — VBL content any host can register.

Plugins begin by extending SpynePlugin — one class, one level, the same composition rule as everything else. Start from the plugin template, wire a channel, and the application can hear it.

CMS and the Behavior Console enter this way too — they ship with the Application Shell.

There's no curated plugin portal yet — plugins move through GitHub and npm.

The catalog is young. The architecture is not.

OPEN SOURCE SpyneJS is open source and free to use.

Everything on this page is available today. All of it is beta — 1.0 comes when the community has vetted it, not before.

npx spyne-cli create-app